using System.Linq.Expressions;
using SqlSugar;
using Digitalmes.Common.Enums;
using Digitalmes.Common.Utils;
using Digitalmes.Domain;

namespace Digitalmes.Sugar;

/// <summary>
/// 基于 SqlSugar 的仓储
/// </summary>
/// <typeparam name="T">实体类型</typeparam>
public class SugarRepository<T> : SimpleClient<T> where T : class, IEntity, new()
{
    protected ITenant Tenant; // 多租户事务、GetConnection、IsAnyConnection等功能

    public SugarRepository(ISqlSugarClient? context = null) : base(context)
    {
        Tenant = context != null ? context.AsTenant() : AppUtils.GetRequiredService<ISqlSugarClient>().AsTenant(); // 用来处理事务
        Context = Tenant.GetConnectionScopeWithAttr<T>(); // 线程安全，作用域 Scope，根据实体配置的 <TenantAttribute> 使用对应的 DB。
    }

    /// <summary>
    /// 分页查询
    /// </summary>
    /// <param name="where">条件</param>
    /// <param name="page">当前页</param>
    /// <param name="limit">每页条数</param>
    /// <param name="order">排序</param>
    /// <param name="orderEnum">枚举，1=desc 2=asc</param>
    /// <returns>集合、总条数、总页数</returns>
    public async Task<(List<T>, int totalItem, int totalPage)> GetPageResultAsync(Expression<Func<T, bool>> where, 
        int page, int limit, Expression<Func<T, object>> order, OrderEnum orderEnum = OrderEnum.Desc)
    {
        RefAsync<int> totalItems = 0;
        var list = await Context.Queryable<T>()
            .Where(where)
            .OrderBy(order, (int)orderEnum == 1 ? OrderByType.Desc : OrderByType.Asc)
            .ToPageListAsync(page, limit, totalItems);
        var sumPage = totalItems != 0 ? (totalItems % page) == 0 ? (totalItems / limit) : (totalItems / limit) + 1 : 0;
        return (list, totalItems, sumPage);
    }

    /// <summary>
    /// 分页查询
    /// </summary>
    /// <param name="where">Expression 条件</param>
    /// <param name="strWhere">string 条件</param>
    /// <param name="page">当前页</param>
    /// <param name="limit">每页条数</param>
    /// <param name="order">排序</param>
    /// <param name="orderEnum">枚举，1=desc 2=asc</param>
    /// <returns>集合、总条数、总页数</returns>
    public async Task<(List<T>, int totalItem, int totalPage)> GetPageResultAsync(Expression<Func<T, bool>> where, string strWhere, 
        int page, int limit, Expression<Func<T, object>> order, OrderEnum orderEnum = OrderEnum.Desc)
    {
        RefAsync<int> totalItems = 0;
        var list = await Context.Queryable<T>()
            .Where(where)
            .WhereIF(!string.IsNullOrEmpty(strWhere), strWhere)
            .OrderBy(order, (int)orderEnum == 1 ? OrderByType.Desc : OrderByType.Asc)
            .ToPageListAsync(page, limit, totalItems);
        var sumPage = totalItems != 0 ? (totalItems % page) == 0 ? (totalItems / limit) : (totalItems / limit) + 1 : 0;
        return (list, totalItems, sumPage);
    }

    /// <summary>
    /// 根据筛选条件，按指定排序获得最新第一条数据
    /// </summary>
    /// <param name="where">筛选条件</param>
    /// <param name="order">排序</param>
    /// <param name="orderEnum">枚举，1=desc 2=asc</param>
    /// <returns></returns>
    public async Task<T?> GetFirstAsync(Expression<Func<T, bool>> where, Expression<Func<T, object>> order, OrderEnum orderEnum = OrderEnum.Desc)
    {
        return await Context.Queryable<T>()
            .Where(where)
            .OrderBy(order, (int)orderEnum == 1 ? OrderByType.Desc : OrderByType.Asc)
            .FirstAsync();
    }

    /// <summary>
    /// 根据条件查询列表
    /// </summary>
    /// <param name="where">筛选条件</param>
    /// <param name="order">排序</param>
    /// <param name="orderEnum">枚举，1=desc 2=asc</param>
    /// <returns></returns>
    public async Task<List<T>> GetListAsync(Expression<Func<T, bool>> where, Expression<Func<T, object>> order, OrderEnum orderEnum = OrderEnum.Desc)
    {
        var query = Context.Queryable<T>()
            .Where(where)
            .OrderBy(order, (int)orderEnum == 1 ? OrderByType.Desc : OrderByType.Asc);
        return await query.ToListAsync();
    }

    /// <summary>
    /// 更新实体指定的列名
    /// </summary>
    /// <param name="entry">实体对象</param>
    /// <param name="updateColumns">要更新的列名</param>
    /// <returns></returns>
    public async Task<bool> UpdateAsync(T entry, Expression<Func<T, object>> updateColumns)
    {
        return await Context.Updateable(entry)
           .UpdateColumns(updateColumns)
           .ExecuteCommandAsync() > 0;
    }

    /// <summary>
    /// 更新实体指定的列名
    /// </summary>
    /// <param name="entries">实体对象集合</param>
    /// <param name="updateColumns">要更新的列名</param>
    /// <returns></returns>
    public async Task<bool> UpdateAsync(List<T> entries, Expression<Func<T, object>> updateColumns)
    {
        return await Context.Updateable(entries)
           .UpdateColumns(updateColumns)
           .ExecuteCommandAsync() > 0;
    }
}
